package com.wcdxg.flow

import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.flowWithLifecycle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
import kotlin.system.measureTimeMillis

const val TAG = "tag"

class MainActivity : AppCompatActivity() {

    private val viewModel by viewModels<MainViewModel>()
    private lateinit var mTvResult: TextView
    private lateinit var mTvResult2: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mTvResult = findViewById(R.id.tv_result)
        mTvResult2 = findViewById(R.id.tv_result_2)

        findViewById<Button>(R.id.btn_get).setOnClickListener {
            launchAndRepeatWithViewLifecycle {
                viewModel.getNetData()
                    .collect {
                        mTvResult2.text = it
                    }
            }
        }

        launchAndRepeatWithViewLifecycle {
            viewModel.eventFlow
                .flowWithLifecycle(this@MainActivity.lifecycle)
                .collect {
                    Log.e(TAG, "repeatOnLifecycle eventFlow: $it")
                    mTvResult.text = it
                    delay(300)
                }

            //不能在一个协程中调用多个Collect 前面一个Collect会挂起协程 导致后面一个无法执行
//                viewModel.uiState
//                    .collect {
//                        Log.e(TAG, "repeatOnLifecycle uiState: $it")
//                        mTvResult2.text = it
//                    }
        }

        //当状态为 STARTED 状态时会开始收集流 并且在 RESUMED 状态时保持收集，最终在进入 STOPPED 状态时结束收集过程
        //不使用repeatOnLifecycle的话 会始终执行collect方法更新View
        launchAndRepeatWithViewLifecycle {
            viewModel.uiState
                .collect {
                    Log.e(TAG, "repeatOnLifecycle uiState: $it")
                    mTvResult2.text = it
                }
        }

        //LiveData的写法
        viewModel.liveDataState.observe(this) {
            Log.e(TAG, "liveDataState: $it")
            mTvResult2.text = it
        }

        lifecycle.addObserver(MyView(this))
    }


    fun testFlow() {
        runBlocking {
            Log.e(TAG, "Flow zip: ---------------------------------")
            val flow1 = flowOf(1, 2, 3).onEach {
                delay(500)
            }

            val flow2 = flowOf("a", "b", "c", "d").onEach {
                delay(15)
            }

            //Zip合并操作符
            flow1.zip(flow2) { i, s ->
                i.toString() + s
            }.collect {
                //其中一个流完成，结果流就完成，并在剩余流上调用cancel 所以flow2中的d没有打印
                //result= 1a 2b 3c
                Log.e(TAG, "onCreate: $it")
            }

            Log.e(TAG, "Flow combine: ---------------------------------")

            //combine  最终合并的流的结果是每个流最近的发设值
            flow1.combine(flow2) { i, s ->
                i.toString() + s
            }.collect {
                //flow1延迟500时 result= 1d 2d 3d  延迟10时 result = 1a 2a 2b 3b 3c 3d
                Log.e(TAG, "onCreate: $it")
            }

            Log.e(TAG, "Flow conflate: ---------------------------------")
            //conflate
            val userTime = measureTimeMillis {
                //measureTimeMillis 测量代码块执行时长
                val flow = flow {
                    for (i in 1..30) {
                        delay(100)
                        emit(i)
                    }
                }

                val result = flow.conflate().onEach {
                    delay(1100)
                }
                //result=[1, 11, 22, 30]
                Log.e(TAG, "onCreate: ${result.toList()}")
            }
            Log.e(TAG, "onCreate: $userTime")

            Log.e(TAG, "Flow debounce: ---------------------------------")
            //debounce 过滤掉给定timeout内的值，始终会发出最新值
            flow {
                emit(1)
                delay(90)
                emit(2)
                delay(90)
                emit(3)
                delay(1010)
                emit(4)
                delay(10)
                emit(5)
                delay(100)
                emit(6)
                delay(1000)
                emit(7)
            }.debounce(1000).collect {
                //result= 3 6 7
                Log.e(TAG, "onCreate: $it")
            }

            Log.e(TAG, "Flow channelFlow: ---------------------------------")
            channelFlow {
                for (i in 1..5) {
                    delay(100)
                    send(i)
                }
            }.collect {
                Log.e(TAG, "onCreate: $it")
            }

            loadData()
                .filter {
                    it > 0
                }
                .onEach {
                    if (it == 3) {
                        throw RuntimeException("error on $it")
                    }
                }
                .onStart {
                    Log.e(TAG, "onStart: ")
                }
                .catch {
                    Log.e(TAG, "catch on: ${it.message}")
                }//catch捕获异常后 onCompletion中不再接收throw
                .onCompletion { cause ->
                    if (cause != null) {
                        Log.e(TAG, "onCompletion: error ${cause.message}")
                    } else {
                        Log.e(TAG, "onCompletion")
                    }
                }
                .collect {
                    Log.e(TAG, "collect: $it")
                }


            //transform操作符可以发射任意值和多次调用emit
            (1..5).asFlow()
                .transform {
                    emit(it * 2)
                    delay(100)
                    emit("emit $it")
                }
                .collect {
                    Log.e(TAG, "transform: $it")
                }

            //take操作符 只取前几个emit发射的值
            (1..5).asFlow()
                .take(3)
                .collect {
                    Log.e(TAG, "take: $it")
                }

            val sum = (1..3).asFlow()
                .map { it * it }
                .reduce { a, b -> a + b }
            Log.e(TAG, "reduce: $sum")
        }
    }

    private fun loadData() = flow {
        for (i in 1..5) {
            delay(300)
            emit(i)
        }
        //切换线程
    }.flowOn(Dispatchers.IO)
}